
%{
#define YYMAXDEPTH  1000000

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <errno.h>
#include "sql_tree.h"

#ifdef WINDOWS
#define inline
#endif

int  yylex();
void yyerror(const char* err);
#define DBG_PRINT

#define DOLLAR_SIGN_TEXT  "$"
#define WON_SIGN_TEXT    "\\"

%}

%locations
%glr-parser
%error_verbose

%union {
  LN_INT64     number;
  double       real_num;
  SQL_NODE_PTR node;
  char *       cptr;
  SQL_STRING_LIST list;
  struct SQL_node_name_t * ext_name;
}

/* common */
%type <list> id_list
%type <cptr> opt_id
%type <cptr> identifier
%type <cptr> opt_as_identifier
%type <number> opt_table_type
%type <number> opt_hint

%type <number> opt_unique
%type <number> all_distinct


/* statements */
%type <node> stmt_list
%type <node> stmt
%type <node> transaction_stmt
%type <node> rename_stmt
%type <node> drop_stmt
%type <node> evaluate_stmt

/* create */
%type <node> create_stmt
%type <number> opt_with_levels_clause
%type <cptr> opt_password
%type <list> opt_groups
%type <list> opt_members

/* delete */
%type <node> delete_stmt
%type <node> opt_where_delete_update

/* alter */
%type <node> alter_stmt
%type <node> alter_clause;
%type <node> alter_attr_default_value_list
%type <number> opt_of_attr_column_method

/* table name and table spec*/
%type <ext_name> opt_table_name
%type <ext_name> table_name
%type <ext_name> table_name_list

%type <node> table_spec_list
%type <node> join_table_spec
%type <node> table_spec
%type <node> ext_table_spec
%type <node> extended_table_spec_list

%type <number> opt_of_inner_left_right

/* field attr and view field attr */
%type <node> opt_view_attr_def_list
%type <node> view_attr_def_list
%type <node> view_attr_def

%type <node> field_attr_def_list
%type <node> field_attr_def
%type <node> constraint_list
%type <node> column_constraint_def
%type <node> of_unique_foreign_check

%type <number> opt_constraint_attr_list
%type <number> constraint_attr_list
%type <number> constraint_attr

%type <number> ref_rule_value
%type <number> ref_rule_list
%type <number> opt_ref_rule_list

%type <list> opt_attr_list
%type <cptr> opt_constraint_id
%type <list> opt_paren_attr_list


/* insert into */
%type <node> insert_stmt
%type <node> insert_value_list
%type <node> insert_value
%type <ext_name> opt_index_column_name_list
%type <ext_name> index_column_name_list
%type <ext_name> index_column_name_list_sub
%type <ext_name> index_column_name
%type <node> opt_using_index_clause
%type <node> insert_stmt_value_clause
%type <node> insert_expression_value_clause

%type <node> insert_expression
%type <ext_name> into_clause_opt

/* update */
%type <node> update_stmt
%type <node> update_assignment_list
%type <node> update_assignment

%type <node> path_expression
%type <node> path_expression_list

/* auther_cmd */
%type <node> auth_stmt
%type <node> author_cmd_list
%type <node> authorized_cmd
%type <number> opt_with_grant_option

/* select and select expression */
%type <node> select_expression
%type <node> select_or_subquery
%type <node> select_stmt
%type <node> csql_query
%type <node> opt_as_query_list
%type <node> query_list
%type <node> search_condition_expression

%type <node> select_list
%type <ext_name> opt_select_param_list
%type <node> alias_enabled_expression_list
%type <ext_name> to_param_list
%type <ext_name> to_param

%type <number> table_op

/* where */
%type <node> opt_where_clause

/* group by */
%type <node> opt_groupby_clause
%type <node> opt_having_clause

/*  order by */
%type <node> opt_orderby_clause
%type <node> sort_spec_list
%type <node> sort_spec

/* expression */
%type <node> expression_list
%type <node> expression_
%type <node> term
%type <node> factor
%type <node> primary
%type <node> case_expr
%type <node> opt_else_expr
%type <node> simple_when_clause_list
%type <node> searched_when_clause_list
%type <node> search_condition
%type <node> boolean_term
%type <node> boolean_factor
%type <node> predicate
%type <node> literal_w_o_param
%type <node> reserved_func

/* expression related */
%type <number> of_avg_max_etc
%type <number> of_leading_trailing_both
%type <number> opt_of_all_some_any
%type <number> comp_op
%type <number> like_op
%type <number> null_op
%type <number> in_op
%type <number> between_op
%type <number> of_distinct_unique

%type <cptr> char_string_literal
%type <cptr> bit_string_literal
%type <node> date_or_time_literal
%type <real_num> monetary_literal
%type <real_num> of_integer_real_literal
%type <node> escape_string_literal
%type <number> host_param_input

/* data type */
%type <number> primitive_type
%type <number> opt_varying
%type <number> opt_prec_2
%type <number> opt_prec_1


/* Token define */
/*{{{*/
%token SQL_ACTION
%token SQL_ADD
%token SQL_ALL
%token SQL_ALTER
%token SQL_AND
%token SQL_ANY
%token SQL_AS
%token SQL_ASC
%token SQL_AT
%token SQL_AVG
%token SQL_ATTRIBUTE

%token SQL_BETWEEN
%token SQL_BIT
%token SQL_BIT_LENGTH
%token SQL_BOTH
%token SQL_BY

%token SQL_CASCADE
%token SQL_CASCADED
%token SQL_CASE
%token SQL_CAST
%token SQL_CHANGE
%token SQL_CHAR
%token SQL_CHARACTER_LENGTH
%token SQL_CHECK
%token SQL_COALESCE
%token SQL_COLUMN
%token SQL_COMMIT
%token SQL_CONNECT
%token SQL_CONSTRAINT
%token SQL_COUNT
%token SQL_CREATE
%token SQL_CROSS
%token SQL_CURRENT
%token SQL_CURRENT_DATE
%token SQL_CURRENT_TIME
%token SQL_CURRENT_TIMESTAMP
%token SQL_CURRENT_USER

%token SQL_DATE
%token SQL_DATETIME
%token SQL_DEFAULT
%token SQL_DEFERRABLE
%token SQL_DEFERRED
%token SQL_DELETE
%token SQL_DESC
%token SQL_DIFFERENCE
%token SQL_DISTINCT
%token SQL_DOUBLE
%token SQL_DROP

%token SQL_ELSE
%token SQL_END
%token SQL_ESCAPE
%token SQL_EXCEPT
%token SQL_EXECUTE
%token SQL_EXISTS
%token SQL_EXTRACT
%token SQL_EVALUATE

%token SQL_FALSE
%token SQL_FLOAT
%token SQL_FOR
%token SQL_FOREIGN
%token SQL_FROM

%token SQL_GRANT
%token SQL_GROUP

%token SQL_HAVING

%token SQL_IMMEDIATE
%token SQL_IN
%token SQL_INDEX
%token SQL_INITIALLY
%token SQL_INNER
%token SQL_INSERT
%token SQL_INTEGER
%token SQL_INTERSECT
%token SQL_INTO
%token SQL_IS

%token SQL_JOIN
%token SQL_KEY

%token SQL_LEADING
%token SQL_LEFT
%token SQL_LEVEL
%token SQL_LIKE
%token SQL_LOCAL
%token SQL_LOWER

%token SQL_MAX
%token SQL_MIN

%token SQL_NATIONAL
%token SQL_NATURAL
%token SQL_NCHAR
%token SQL_NO
%token SQL_NOT
%token SQL_NONE
%token SQL_NULL
%token SQL_NULLIF
%token SQL_NUMERIC

%token SQL_OCTET_LENGTH
%token SQL_OF
%token SQL_ON
%token SQL_ONLY
%token SQL_OPTION
%token SQL_OR
%token SQL_ORDER
%token SQL_OUTER

%token SQL_POSITION
%token SQL_PRECISION
%token SQL_PRIMARY
%token SQL_PRIOR
%token SQL_PRIVILEGES

%token SQL_REFERENCES
%token SQL_RENAME
%token SQL_RESTRICT
%token SQL_REVOKE
%token SQL_RIGHT
%token SQL_ROLLBACK

%token SQL_SELECT
%token SQL_SET
%token SQL_SMALLINT
%token SQL_SOME
%token SQL_SUBSTRING
%token SQL_SUM

%token SQL_TABLE
%token SQL_THEN
%token SQL_TIME
%token SQL_TIMESTAMP
%token SQL_TO
%token SQL_TRAILING
%token SQL_TRANSLATE
%token SQL_TRIM
%token SQL_TRUE

%token SQL_UNION
%token SQL_UNIQUE
%token SQL_UPDATE
%token SQL_UPPER
%token SQL_USER
%token SQL_USING

%token SQL_VALUES
%token SQL_VARCHAR
%token SQL_VARYING
%token SQL_VIEW

%token SQL_WHEN
%token SQL_WHERE
%token SQL_WITH
%token SQL_WORK

%token SQL_DOLLAR_SIGN
%token SQL_WON_SIGN

%token SQL_RIGHT_ARROW
%token SQL_STRCAT
%token SQL_COMP_NOT_EQ
%token SQL_COMP_GE
%token SQL_COMP_LE

%token SQL_EQUAL_SIGN
%token SQL_NOT_EQUAL_SIGN

%token <cptr> SQL_GROUPS
%token <cptr> SQL_MEMBERS
%token <cptr> SQL_PASSWORD
%token <cptr> SQL_STDDEV

%token <cptr> SQL_ID_NAME
%token <cptr> SQL_BracketDelimitedIdName
%token <number>   SQL_UNSIGNED_INTEGER
%token <number>   SQL_PARAM_HEADER
%token <real_num> SQL_UNSIGNED_REAL
%token <cptr> SQL_CHAR_STRING
%token <cptr> SQL_NCHAR_STRING
%token <cptr> SQL_BIT_STRING
%token <cptr> SQL_HEX_STRING
%token <number> SQL_HINT

/*}}}*/

%%

stmt_done
  : stmt_list
    {{
      SQL_this_parser->statements = $1;
    DBG_PRINT}}
  | /* empty */
    {{
      SQL_this_parser->statements = NULL;
    DBG_PRINT}}
  ;

stmt_list
  : stmt_list stmt
    {{
      $$ = sql_add_node_to_list ($1, $2);

    DBG_PRINT}}
  | stmt
    {{
      
      $$ = $1;
      
    DBG_PRINT}}
  ;

stmt
  : create_stmt
    { $$ = $1; }
  | alter_stmt
    { $$ = $1; }
  | rename_stmt
    { $$ = $1; }
  | drop_stmt
    { $$ = $1; }
  | evaluate_stmt
    { $$ = $1; }
  | csql_query
    { $$ = $1; }
  | insert_stmt
    { $$ = $1; }
  | update_stmt
    { $$ = $1; }
  | delete_stmt
    { $$ = $1; }
  | auth_stmt
    { $$ = $1; }
  | transaction_stmt
    { $$ = $1; }
  ;

create_stmt
  : SQL_CREATE opt_hint SQL_TABLE table_name '(' field_attr_def_list ')'
    {{

      SQL_NODE_PTR node = sql_new_node ( S_NODE_CREATE_TABLE );

      if (node)
        {
          node->dt.create_table.hints  = (int)$2;
          node->dt.create_table.name   = $4;
          node->dt.create_table.attr_def_list = $6;
        }

      $$ = node;

    DBG_PRINT}}

  | SQL_CREATE SQL_VIEW table_name opt_view_attr_def_list opt_as_query_list opt_with_levels_clause
    {{

      SQL_NODE_PTR node = sql_new_node ( S_NODE_CREATE_VIEW );
      $$ = node;

    DBG_PRINT}}

  | SQL_CREATE opt_hint opt_unique SQL_INDEX opt_id SQL_ON table_name index_column_name_list
    {{
      SQL_NODE_PTR node = sql_new_node ( S_NODE_CREATE_INDEX );
      
      $$ = node;

    DBG_PRINT}}

  | SQL_CREATE SQL_USER identifier opt_password opt_groups opt_members
    {{

      SQL_NODE_PTR node = sql_new_node ( S_NODE_CREATE_USER );

      $$ = node;

    DBG_PRINT}}
  ;

alter_stmt
  : SQL_ALTER opt_hint opt_table_type table_name alter_clause
    {{
    DBG_PRINT}}

  | SQL_ALTER SQL_USER identifier SQL_PASSWORD char_string_literal
    {{
    
      SQL_NODE_PTR node = sql_new_node ( S_NODE_ALTER_USER );
      
      $$ = node;

    DBG_PRINT}}

  | SQL_ALTER opt_hint opt_unique SQL_INDEX SQL_ON table_name index_column_name_list
    {{
    
      SQL_NODE_PTR node = sql_new_node ( S_NODE_ALTER_INDEX );
      
      $$ = node;

    DBG_PRINT}}

  | SQL_ALTER opt_hint opt_unique SQL_INDEX identifier SQL_ON table_name opt_index_column_name_list
    {{
    
      SQL_NODE_PTR node = sql_new_node ( S_NODE_ALTER_INDEX );
      
      $$ = node;

    DBG_PRINT}}

  | SQL_ALTER opt_hint opt_unique SQL_INDEX identifier
    {{

      SQL_NODE_PTR node = sql_new_node ( S_NODE_ALTER_INDEX );
      
      $$ = node;

    DBG_PRINT}}
  ;

rename_stmt
  : SQL_RENAME opt_table_type table_name SQL_AS table_name
    {{
      SQL_NODE_PTR node = sql_new_node ( S_NODE_RENAME );
      
      $$ = node;

    DBG_PRINT}}
  ;

drop_stmt
  : SQL_DROP opt_table_type table_name_list
    {{

      SQL_NODE_PTR node = sql_new_node ( S_NODE_DROP );
      
      $$ = node;

    DBG_PRINT}}

  | SQL_DROP opt_hint opt_unique SQL_INDEX SQL_ON table_name index_column_name_list
    {{
      SQL_NODE_PTR node = sql_new_node ( S_NODE_DROP );
      $$ = node;

    DBG_PRINT}}

  | SQL_DROP opt_hint opt_unique SQL_INDEX identifier SQL_ON table_name opt_index_column_name_list
    {{

      SQL_NODE_PTR node = sql_new_node ( S_NODE_DROP );
      $$ = node;

    DBG_PRINT}}

  | SQL_DROP opt_hint opt_unique SQL_INDEX identifier
    {{

      SQL_NODE_PTR node = sql_new_node ( S_NODE_DROP );
      $$ = node;

    DBG_PRINT}}

  | SQL_DROP SQL_USER identifier
    {{

      SQL_NODE_PTR node = sql_new_node ( S_NODE_DROP );
      $$ = node;

    DBG_PRINT}}
  ;

opt_unique
  : /* empty */
    {{

      $$ = 0;

    DBG_PRINT}}
  | SQL_UNIQUE
    {{

      $$ = 1;

    DBG_PRINT}}
  ;

opt_index_column_name_list
  : /* empty */
    {{

      $$ = NULL;

    DBG_PRINT}}
  | index_column_name_list
    {{

      $$ = $1;

    DBG_PRINT}}
  ;

index_column_name_list
  : '(' index_column_name_list_sub ')'
    {{

      $$ = $2;

    DBG_PRINT}}
  ;

index_column_name_list_sub
  : index_column_name_list_sub ',' index_column_name
    {{
      $3->next = $1;
      $$ = $3;

    DBG_PRINT}}
  | index_column_name
    {{
    
      $$ = $1;

    DBG_PRINT}}
  ;

index_column_name
  : identifier
    {{
      struct SQL_node_name_t * name = sql_new_name();
      name->name   = $1;
      
      $$ = name;

    DBG_PRINT}}
  | identifier SQL_ASC
    {{

      struct SQL_node_name_t * name = sql_new_name();
      name->name   = $1;
      name->flag   = SQL_ASC;
      
      $$ = name;
      
    DBG_PRINT}}
  | identifier SQL_DESC
    {{
      struct SQL_node_name_t * name = sql_new_name();
      name->name   = $1;
      name->flag   = SQL_DESC;
      
      $$ = name;
      
    DBG_PRINT}}
  ;

table_spec_list
  : table_spec_list  ',' table_spec
    {{

      $$ = sql_add_node_to_list ($1, $3);

    DBG_PRINT}}

  | table_spec
    {{

      $$ = $1;

    DBG_PRINT}}
  ;

extended_table_spec_list
  : extended_table_spec_list ',' table_spec
    {{

      $$ = sql_add_node_to_list ($1, $3);

    DBG_PRINT}}

  | extended_table_spec_list join_table_spec
    {{

      $$ = sql_add_node_to_list ($1, $2);

    DBG_PRINT}}
  | table_spec
    {{

      $$ = $1;

    DBG_PRINT}}
  ;

join_table_spec
  : SQL_CROSS SQL_JOIN table_spec
    {{
    DBG_PRINT}}

  | opt_of_inner_left_right SQL_JOIN table_spec SQL_ON search_condition
    {{
    DBG_PRINT}}
  ;

opt_of_inner_left_right
  : /* empty */
    {{

      $$ = S_JOIN_INNER;

    DBG_PRINT}}
  | SQL_INNER opt_outer
    {{

      $$ = S_JOIN_INNER;

    DBG_PRINT}}
  | SQL_LEFT opt_outer
    {{

      $$ = S_JOIN_LEFT_OUTER;

    DBG_PRINT}}
  | SQL_RIGHT opt_outer
    {{

      $$ = S_JOIN_RIGHT_OUTER;

    DBG_PRINT}}
  ;

opt_outer
  : /* empty */
  | SQL_OUTER
  ;

ext_table_spec
  : table_name
    {{
      SQL_NODE_PTR node = sql_new_node (S_NODE_NAME);
      
      if (node)
      {
        node->dt.name = *$1;
      }
      
      $$ = node;
    }}
  | '(' csql_query ')'
    {{
      $$ = $2;
    }}
  ;

table_spec
  : ext_table_spec
    {{
    
      SQL_NODE_PTR node = sql_new_node (S_NODE_SPEC);
      
      if (node)
      {
        node->dt.table_spec.spec = $1;
        node->dt.table_spec.as_name = NULL;
      };
      
      $$ = node;
      
    DBG_PRINT}}
  | ext_table_spec opt_as identifier '(' id_list ')' 
    {{
    
      SQL_NODE_PTR node = sql_new_node (S_NODE_SPEC);
      
      if (node)
      {
        node->dt.table_spec.spec = $1;
        node->dt.table_spec.as_name = $3;
      };
      
      $$ = node;
      
    DBG_PRINT}}
  | ext_table_spec opt_as identifier
    {{
    
      SQL_NODE_PTR node = sql_new_node (S_NODE_SPEC);
      
      if (node)
      {
        node->dt.table_spec.spec = $1;
        node->dt.table_spec.as_name = $3;
      };
      
      $$ = node;
      
    DBG_PRINT}}
  ;

opt_as
  : /* empty */
  | SQL_AS
  ;

table_name_list
  : table_name_list ',' table_name
    {{
      $1->next = $3;
      $$ = $3;
    DBG_PRINT}}

  | table_name
    {{

      $$ = $1;

    DBG_PRINT}}
  ;

table_name
  : identifier '.' identifier
    {{

      struct SQL_node_name_t * name = sql_new_name();
      name->name   = $3;
      name->prefix = $1;

      $$ = name;
      
    DBG_PRINT}}
  | identifier
    {{
      struct SQL_node_name_t * name = sql_new_name();
      
      name->name   = $1;
      
      $$ = name;

    DBG_PRINT}}
  ;

opt_table_type
  : /* empty */
    {{

      $$ = S_SQL_EMPTY;

    DBG_PRINT}}
  | SQL_VIEW
    {{

      $$ = S_SQL_VIEW;

    DBG_PRINT}}
  | SQL_TABLE
    {{

      $$ = S_SQL_TABLE;

    DBG_PRINT}}
  ;

alter_clause
  : SQL_ADD opt_of_column_attribute field_attr_def_list
    {{
      $$ = NULL;
    DBG_PRINT}}

  | SQL_DROP opt_of_attr_column_method id_list 
    {{
      $$ = NULL;
    DBG_PRINT}}

  | SQL_DROP SQL_CONSTRAINT identifier
    {{
      $$ = NULL;
    DBG_PRINT}}

  | SQL_CHANGE opt_of_column_attribute field_attr_def_list
    {{
      $$ = NULL;
    DBG_PRINT}}

  | SQL_CHANGE alter_attr_default_value_list
    {{
      $$ = NULL;
    DBG_PRINT}}

  | SQL_RENAME opt_of_attr_column_method identifier SQL_AS identifier 
    {{
      $$ = NULL;
    DBG_PRINT}}
  ;

opt_of_attr_column_method
  : /* empty */
    {{

      $$ = 0;

    DBG_PRINT}}
  | SQL_ATTRIBUTE
    {{

      $$ = SQL_ATTRIBUTE;

    DBG_PRINT}}
  | SQL_COLUMN
    {{

      $$ = SQL_COLUMN;

    DBG_PRINT}}
  ;

opt_of_column_attribute
  : /* empty */
  | SQL_COLUMN
  | SQL_ATTRIBUTE
  ;

alter_attr_default_value_list
  : alter_attr_default_value_list ',' identifier SQL_DEFAULT expression_
    {{
      SQL_NODE_PTR node = sql_new_node (0);

      $$ = sql_add_node_to_list ($1, node);

    DBG_PRINT}}
  | identifier SQL_DEFAULT expression_
    {{
      SQL_NODE_PTR node = sql_new_node (0);
      
      $$ = sql_new_list_node_and_add (node);
    DBG_PRINT}}
  ;

insert_stmt
  : SQL_INSERT opt_hint SQL_INTO table_name opt_attr_list insert_stmt_value_clause into_clause_opt
    {{
    DBG_PRINT}}
  ;

insert_expression
  : SQL_INSERT opt_hint SQL_INTO table_name opt_attr_list insert_expression_value_clause
    {{
    DBG_PRINT}}

  | '(' SQL_INSERT opt_hint SQL_INTO table_name opt_attr_list insert_expression_value_clause into_clause_opt ')'
    {{
    DBG_PRINT}}
  ;

opt_attr_list
  : /* empty */
    {{

      $$.size = 0;

    DBG_PRINT}}
  | '(' ')'
    {{

      $$.size = 0;

    DBG_PRINT}}
  | '(' id_list ')'
    {{

      $$ = $2;

    DBG_PRINT}}
  ;


insert_stmt_value_clause
  : insert_expression_value_clause
    {{

      $$ = $1;

    DBG_PRINT}}
  | csql_query
    {{
    $$ = $1;
    DBG_PRINT}}
  ;

insert_expression_value_clause
  : SQL_VALUES '(' insert_value_list ')'
    {{
    DBG_PRINT}}

  | SQL_VALUES '(' ')'
    {{
    DBG_PRINT}}
    
  | SQL_DEFAULT SQL_VALUES
    {{
    DBG_PRINT}}

  | SQL_DEFAULT
    {{
    DBG_PRINT}}
  ;

into_clause_opt
  : /* empty */
    {{

      $$ = NULL;

    DBG_PRINT}}
  | SQL_INTO to_param
    {{

      $$ = $2;

    DBG_PRINT}}
  | SQL_TO to_param
    {{

      $$ = $2;

    DBG_PRINT}}
  ;

insert_value_list
  : insert_value_list ',' insert_value
    {{

      $$ = sql_add_node_to_list ($1, $3);

    DBG_PRINT}}
  | insert_value
    {{

      $$ = sql_new_list_node_and_add ($1);

    DBG_PRINT}}
  ;

insert_value
  : select_stmt
    {{

      $$ = $1;

    DBG_PRINT}}
  | expression_
    {{

      $$ = $1;

    DBG_PRINT}}
  ;

update_stmt
  : SQL_UPDATE 
    opt_hint 
    table_name 
    opt_as_identifier
    SQL_SET 
    update_assignment_list
    opt_where_delete_update
    opt_using_index_clause
    {{
      SQL_NODE_PTR node = sql_new_node (S_NODE_UPDATE);
      
      if (node)
      {
        node->dt.update.hints = (int)$2;
        node->dt.update.table_name = $3;
        node->dt.update.as_id = $4;
        node->dt.update.update_list = $6;
        node->dt.update.where_clause = $7;
        node->dt.update.using_index  = $8;
      };
      
      $$ = node;
    DBG_PRINT}}
  ;


opt_where_delete_update
  : /* empty */
    {{
      $$ = NULL;
    DBG_PRINT}}

  | SQL_WHERE search_condition
    {{
      $$ = $2;
    DBG_PRINT}}

  | SQL_WHERE SQL_CURRENT SQL_OF identifier
    {{
      $$ = NULL;
    DBG_PRINT}}
  ;

opt_as_identifier
  : /* empty */
    {{

      $$ = NULL;

    DBG_PRINT}}
  | SQL_AS identifier
    {{

      $$ = $2;

    DBG_PRINT}}
  | identifier
    {{

      $$ = $1;

    DBG_PRINT}}
  ;

update_assignment_list
  : update_assignment_list ',' update_assignment
    {{

      $$ = sql_add_node_to_list ($1, $3);

    DBG_PRINT}}
  | update_assignment
    {{

      $$ = sql_new_list_node_and_add ($1);

    DBG_PRINT}}
  ;

update_assignment
  : path_expression '=' expression_
    {{
    DBG_PRINT}}
  | '(' path_expression_list ')' '=' primary
    {{
    DBG_PRINT}}
  ;

path_expression_list
  : path_expression_list ',' path_expression
    {{

      $$ = sql_add_node_to_list ($1, $3);

    DBG_PRINT}}
  | path_expression
    {{

      $$ = sql_new_list_node_and_add ($1);

    DBG_PRINT}}
  ;

delete_stmt
  : SQL_DELETE        /* $1 */
    opt_hint       /* $2 */
    opt_table_name       /* $3 */
    SQL_FROM           /* $4 */
    table_spec_list       /* $5 */
    opt_where_delete_update       /* $6 */
    opt_using_index_clause     /* $7 */
    {{
    DBG_PRINT}}
  ;

opt_table_name
  : /* empty */
    {{

      $$ = NULL;

    DBG_PRINT}}
  | table_name
    {{

      $$ = $1;

    DBG_PRINT}}
  ;

auth_stmt
  : SQL_GRANT author_cmd_list SQL_ON table_name_list SQL_TO id_list opt_with_grant_option
    {{
    DBG_PRINT}}

  | SQL_GRANT author_cmd_list SQL_TO id_list SQL_ON table_name_list opt_with_grant_option
    {{
    DBG_PRINT}}

  | SQL_REVOKE author_cmd_list SQL_ON table_name_list SQL_FROM id_list
    {{
    DBG_PRINT}}

  | SQL_REVOKE author_cmd_list SQL_FROM id_list SQL_ON table_name_list
    {{
    DBG_PRINT}}
  ;

opt_with_grant_option
  : /* empty */
    {{

      $$ = 0;

    DBG_PRINT}}
  | SQL_WITH SQL_GRANT SQL_OPTION
    {{

      $$ = 1;

    DBG_PRINT}}
  ;

author_cmd_list
  : author_cmd_list ',' authorized_cmd
    {{

      $$ = sql_add_node_to_list ($1, $3);

    DBG_PRINT}}
  | authorized_cmd
    {{

      $$ = sql_new_list_node_and_add ($1);

    DBG_PRINT}}
  ;

authorized_cmd
  : SQL_SELECT
    {{
    DBG_PRINT}}

  | SQL_INSERT
    {{
    DBG_PRINT}}

  | SQL_INDEX
    {{
    DBG_PRINT}}

  | SQL_DELETE
    {{
    DBG_PRINT}}

  | SQL_UPDATE '(' id_list ')'
    {{
    DBG_PRINT}}

  | SQL_UPDATE
    {{
    DBG_PRINT}}

  | SQL_ALTER
    {{
    DBG_PRINT}}

  | SQL_ADD
    {{
    DBG_PRINT}}

  | SQL_DROP
    {{
    DBG_PRINT}}

  | SQL_EXECUTE
    {{
    DBG_PRINT}}

  | SQL_REFERENCES
    {{
    DBG_PRINT}}

  | SQL_ALL SQL_PRIVILEGES
    {{
    DBG_PRINT}}

  | SQL_ALL
    {{
    DBG_PRINT}}
  ;

opt_password
  : /* empty */
    {{

      $$ = NULL;

    DBG_PRINT}}
  | SQL_PASSWORD char_string_literal
    {{

      $$ = $2;

    DBG_PRINT}}
  ;

opt_groups
  : /* empty */
    {{

      $$.size = 0;

    DBG_PRINT}}
  | SQL_GROUPS id_list
    {{

      $$ = $2;

    DBG_PRINT}}
  ;

opt_members
  : /* empty */
    {{

      $$.size = 0;

    DBG_PRINT}}
  | SQL_MEMBERS id_list
    {{

      $$ = $2;

    DBG_PRINT}}
  ;

opt_view_attr_def_list
  : /* empty */
    {{

      $$ = NULL;

    DBG_PRINT}}
  | '(' view_attr_def_list ')'
    {{

      $$ = $2;

    DBG_PRINT}}
  ;

opt_as_query_list
  : /* empty */
    {{

      $$ = NULL;

    DBG_PRINT}}
  | SQL_AS query_list
    {{

      $$ = $2;

    DBG_PRINT}}
  ;

opt_with_levels_clause
  : /* empty */
    {{

      $$ = S_WITH_LEVEL_EMPTY;

    DBG_PRINT}}
  | SQL_WITH SQL_LOCAL SQL_CHECK SQL_OPTION
    {{

      $$ = S_WITH_LEVEL_LOCAL;

    DBG_PRINT}}
  | SQL_WITH SQL_CASCADED SQL_CHECK SQL_OPTION
    {{

      $$ = S_WITH_LEVEL_CASCADED;

    DBG_PRINT}}
  | SQL_WITH SQL_CHECK SQL_OPTION
    {{

      $$ = S_WITH_LEVEL_CASCADED;

    DBG_PRINT}}
  ;

query_list
  : query_list ',' csql_query
    {{

      $$ = sql_add_node_to_list ($1, $3);

    DBG_PRINT}}
  | csql_query
    {{

      $$ = $1;

    DBG_PRINT}}
  ;

opt_constraint_id
  : /* empty */
    {{

      $$ = NULL;

    DBG_PRINT}}
  | SQL_CONSTRAINT identifier
    {{

      $$ = $2;

    DBG_PRINT}}
  ;

of_unique_foreign_check
  : SQL_PRIMARY SQL_KEY '(' id_list ')'
    {{

      $$ = NULL;

    DBG_PRINT}}

  | SQL_UNIQUE '(' id_list ')'
    {{

      $$ = NULL;

    DBG_PRINT}}

  | SQL_FOREIGN SQL_KEY '(' id_list ')' SQL_REFERENCES table_name opt_paren_attr_list opt_ref_rule_list
    {{

      $$ = NULL;

    DBG_PRINT}}

  | SQL_CHECK '(' search_condition ')'
    {{

      $$ = NULL;

    DBG_PRINT}}
  ;

opt_constraint_attr_list
  : /* empty */
    {{
    $$ = 0;
    DBG_PRINT}}

  | constraint_attr_list
    {{
      $$ = $1;
    DBG_PRINT}}
  ;

constraint_attr_list
  : constraint_attr_list ',' constraint_attr
    {{

    $$ = $1 | $3;

    DBG_PRINT}}

  | constraint_attr
    {{

      $$ = $1;

    DBG_PRINT}}
  ;

opt_paren_attr_list
  : /* empty */
    {{

      $$.size = 0;

    DBG_PRINT}}
  | '(' id_list ')'
    {{

      $$ = $2;

    DBG_PRINT}}
  ;

opt_ref_rule_list
  : /* empty */
    {{
      $$ = 0;
    DBG_PRINT}}
  | ref_rule_list
    {{
      $$ = $1;
      
    DBG_PRINT}}
  ;

ref_rule_value
  : SQL_ON SQL_DELETE SQL_CASCADE
    {{
      $$ = S_RULE_DELETE_CASCADE;
    DBG_PRINT}}

  | SQL_ON SQL_DELETE SQL_NO SQL_ACTION
    {{
      $$ = S_RULE_DELETE_NO_ACTION;
    DBG_PRINT}}

  | SQL_ON SQL_DELETE SQL_RESTRICT
    {{
      $$ = S_RULE_DELETE_RESTRICT;
    DBG_PRINT}}

  | SQL_ON SQL_UPDATE SQL_NO SQL_ACTION
    {{
      $$ = S_RULE_UPDATE_NO_ACTION;
    DBG_PRINT}}

  | SQL_ON SQL_UPDATE SQL_RESTRICT
    {{
      $$ = S_RULE_UPDATE_RESTRICT;
    DBG_PRINT}}

ref_rule_list
  : ref_rule_list ref_rule_value
    {{
      $$ = $1 | $2;
    DBG_PRINT}}

  | ref_rule_value
    {{
      $$ = $1;
    DBG_PRINT}}
  ;

/* bool_deferrable, deferrable value, bool_initially_deferred, initially_deferred value */
constraint_attr
  : SQL_NOT SQL_DEFERRABLE
    {{
      $$ = S_CONSTRAINT_NOT_DEFERRABLE;
    DBG_PRINT}}
  | SQL_DEFERRABLE
    {{
      $$ = S_CONSTRAINT_DEFERRABLE;
    DBG_PRINT}}
  | SQL_INITIALLY SQL_DEFERRED
    {{
      $$ = S_CONSTRAINT_INITIALLY_DEFERRED;
    DBG_PRINT}}
  | SQL_INITIALLY SQL_IMMEDIATE
    {{
      $$ = S_CONSTRAINT_INITIALLY_IMMEDIATE;
    DBG_PRINT}}
  ;

view_attr_def_list
  : view_attr_def_list ',' view_attr_def
    {{

      $$ = sql_add_node_to_list ($1, $3);

    DBG_PRINT}}
  | view_attr_def
    {{

      $$ = sql_new_list_node_and_add ($1);

    DBG_PRINT}}
  ;

view_attr_def
  : field_attr_def
    {{

      $$ = $1;

    DBG_PRINT}}
  | identifier
    {{
      $$ = NULL;
    DBG_PRINT}}
  ;

field_attr_def_list
  : field_attr_def_list ','  field_attr_def
    {{

      $$ = sql_add_node_to_list ($1, $3);

    DBG_PRINT}}
  | field_attr_def
    {{

      $$ = sql_new_list_node_and_add ($1);

    DBG_PRINT}}
  ;

field_attr_def
  : opt_constraint_id of_unique_foreign_check opt_constraint_attr_list
    {{
      SQL_NODE_PTR node = sql_new_node (S_NODE_FIELD_DEF);
      
      if (node)
      {
      }
      
      $$ = node;
    DBG_PRINT}}
  | identifier primitive_type constraint_list
    {{
      SQL_NODE_PTR node = sql_new_node (S_NODE_FIELD_DEF);
      
      if (node)
      {
        node->dt.field_def.name = $1;
        node->dt.field_def.type = $2;
      }
      
      $$ = node;
    DBG_PRINT}}

  | identifier primitive_type
    {{
      SQL_NODE_PTR node = sql_new_node (S_NODE_FIELD_DEF);
      if (node)
      {
        node->dt.field_def.name = $1;
        node->dt.field_def.type = $2;
      }
      $$ = node;
    DBG_PRINT}}
  ;

constraint_list
  : constraint_list column_constraint_def
    {{
      $$ = sql_add_node_to_list ($1,$2);
    DBG_PRINT}}

  | column_constraint_def
    {{
      $$ = sql_new_list_node_and_add ($1);
    DBG_PRINT}}
  ;

column_constraint_def
  : opt_constraint_id SQL_UNIQUE opt_constraint_attr_list
    {{
    DBG_PRINT}}

  | opt_constraint_id SQL_PRIMARY SQL_KEY opt_constraint_attr_list
    {{
    DBG_PRINT}}

  | opt_constraint_id SQL_NULL opt_constraint_attr_list
    {{
    DBG_PRINT}}

  | opt_constraint_id SQL_NOT SQL_NULL opt_constraint_attr_list
    {{
    DBG_PRINT}}

  | opt_constraint_id SQL_CHECK '(' search_condition ')' opt_constraint_attr_list
    {{
    DBG_PRINT}}

  | opt_constraint_id      /* 1 */
    SQL_FOREIGN        /* 2 */
    SQL_KEY          /* 3 */
    SQL_REFERENCES        /* 4 */
    table_name        /* 5 */
    opt_paren_attr_list      /* 6 */
    opt_ref_rule_list      /* 7 */
    opt_constraint_attr_list    /* 8 */
    {{
    DBG_PRINT}}
  ;

transaction_stmt
  : SQL_COMMIT
    {{
    DBG_PRINT}}

  | SQL_COMMIT SQL_WORK
    {{
    DBG_PRINT}}

  | SQL_ROLLBACK
    {{
    DBG_PRINT}}

  | SQL_ROLLBACK SQL_WORK
    {{
    DBG_PRINT}}
  ;

evaluate_stmt
  : SQL_EVALUATE expression_ into_clause_opt
    {{
    DBG_PRINT}}
  ;

opt_plus
  : /* empty */
  | '+'
  ;

csql_query
  : select_expression opt_orderby_clause
    {{
      if ($2)
      {
        // TODO 
      }
      else
      {
         $$ = $1;
      }
    DBG_PRINT}}
  ;

select_expression
  : select_expression table_op select_or_subquery
    {{
      $$ = sql_make_expression ( $2, $1, $3, NULL);
    DBG_PRINT}}

  | select_or_subquery
    {{

      $$ = $1;

    DBG_PRINT}}
  ;

table_op
  : SQL_UNION all_distinct
    {{
      
    DBG_PRINT}}

  | SQL_DIFFERENCE all_distinct
    {{
    DBG_PRINT}}

  | SQL_EXCEPT all_distinct
    {{
    DBG_PRINT}}

  | SQL_INTERSECT all_distinct
    {{
    DBG_PRINT}}
  ;

select_or_subquery
  : select_stmt
    {{

      $$ = $1;

    DBG_PRINT}}
  | '(' csql_query ')'
    {{

      $$ = $2;

    DBG_PRINT}}
  ;

select_stmt
  :
  SQL_SELECT                      /* $1 */
  opt_hint                        /* $2 */
  all_distinct                    /* $3 */
  select_list                     /* $4 */
  opt_select_param_list           /* $5 */
  SQL_FROM                        /* $6 */
  extended_table_spec_list        /* $7 */
  opt_where_clause                /* $8 */
  opt_groupby_clause              /* $9 */
  opt_having_clause               /* $10 */
  opt_using_index_clause          /* $11 */
    {{
      SQL_NODE_PTR node = sql_new_node (S_NODE_SELECT);
      
      if (node)
      {
        node->dt.select.hints       = (SQL_HINT_TYPE)$2;
        node->dt.select.distinct    = (unsigned)$3;
        node->dt.select.select_list = $4;
        node->dt.select.to_param    = $5;
        node->dt.select.spec_list   = $7;
        node->dt.select.where_clause= $8;
        node->dt.select.group_by    = $9;
        node->dt.select.having      = $10;
        node->dt.select.using_index = $11;
      };
      
      $$ = node;
    DBG_PRINT}}
  ;

opt_select_param_list
  : /* empty */
    {{

      $$ = NULL;

    DBG_PRINT}}
  | SQL_INTO to_param_list
    {{

      $$ = $2;

    DBG_PRINT}}
  | SQL_TO to_param_list
    {{

      $$ = $2;

    DBG_PRINT}}
  ;

opt_hint
  : /* empty */
    {{
      $$ = 0;
    }}

  | opt_hint SQL_HINT
    {{
      $$ = $1 | $2;
    DBG_PRINT}}

  | SQL_HINT
    {{
    $$ = $1;
    DBG_PRINT}}
  ;

all_distinct
  : /* empty */
    {{

      $$ = 0;

    DBG_PRINT}}
  | SQL_ALL
    {{

      $$ = SQL_ALL;

    DBG_PRINT}}
  | SQL_DISTINCT
    {{

      $$ = SQL_DISTINCT;

    DBG_PRINT}}
  | SQL_UNIQUE
    {{

      $$ = SQL_UNIQUE;

    DBG_PRINT}}
  ;

select_list
  : '*'
    {{
      SQL_NODE_PTR node = sql_new_node (S_NODE_NAME);
      if (node)
      {
        node->dt.name.name = "*";
        node->dt.name.prefix = NULL;
        node->dt.name.flag   = 2;
      };
      $$ = node;
    DBG_PRINT}}

  | alias_enabled_expression_list
    {{
      $$ = $1;
    DBG_PRINT}}
  ;

alias_enabled_expression_list
  : alias_enabled_expression_list  ',' expression_ opt_as_identifier
    {{
      $3->dt.expr.as_name = $4;
      
      $$ = sql_add_node_to_list ($1, $3);

    DBG_PRINT}}

  | expression_ opt_as_identifier
    {{

      $1->dt.expr.as_name = $2;

      $$ = $1;

    DBG_PRINT}}
  ;

expression_list
  : expression_list  ',' expression_
    {{

      $$ = sql_add_node_to_list ($1, $3);

    DBG_PRINT}}
  | expression_
    {{

      $$ = sql_new_list_node_and_add ($1);

    DBG_PRINT}}
  ;

to_param_list
  : to_param_list ',' to_param
    {{
      $3->next = $1;
      $$ = $3;

    DBG_PRINT}}
  | to_param
    {{

      $$ = $1;

    DBG_PRINT}}
  ;

to_param
  : '?'
    {{
      struct SQL_node_name_t * name = sql_new_name();
      if (name)
      {
        name->name = "?";
      }
      $$ = name;
    DBG_PRINT}}

  | SQL_PARAM_HEADER
    {{
      struct SQL_node_name_t * name = sql_new_name();
      if (name)
      {
        name->name = "?:";
        name->flag = (int)$1;
      }
      $$ = name;
    DBG_PRINT}}

  | ':' identifier
    {{
      struct SQL_node_name_t * name = sql_new_name();
      if (name)
      {
        name->name = $2;
      }
      $$ = name;
    DBG_PRINT}}

  | identifier
    {{
      struct SQL_node_name_t * name = sql_new_name();
      if (name)
      {
        name->name = $1;
      }
      $$ = name;
    DBG_PRINT}}
  ;


host_param_input
  : '?'
    {{
      $$ = -1;
    DBG_PRINT}}
  | SQL_PARAM_HEADER
    {{
      $$ = $1;
    DBG_PRINT}}
  ;

opt_where_clause
  : /* empty */
    {{

      $$ = NULL;

    DBG_PRINT}}
  | SQL_WHERE search_condition
    {{
      $$ = $2;
    DBG_PRINT}}
  ;

opt_groupby_clause  
  : /* empty */
    {{

      $$ = NULL;

    DBG_PRINT}}
  | SQL_GROUP SQL_BY expression_list
    {{
      $$ = $3;
    DBG_PRINT}}
  ;

opt_having_clause
  : /* empty */
    {{

      $$ = NULL;

    DBG_PRINT}}

  | SQL_HAVING search_condition
    {{
      
      $$ = $2;
      
    DBG_PRINT}}
  ;

opt_using_index_clause
  : /* empty */
    {{

      $$ = NULL;

    DBG_PRINT}}
  | SQL_USING SQL_INDEX table_name_list
    {{

      $$ = NULL;

    DBG_PRINT}}

  | SQL_USING SQL_INDEX SQL_NONE
    {{

    DBG_PRINT}}

  | SQL_USING SQL_INDEX SQL_ALL SQL_EXCEPT table_name_list
    {{
    DBG_PRINT}}
  ;


opt_orderby_clause
  : /* empty */
    {{
       $$ = NULL; 
    }}
  | SQL_ORDER SQL_BY sort_spec_list
    {{
      
      $$ = $3;
      
    DBG_PRINT}}
  | SQL_ORDER SQL_BY sort_spec_list SQL_FOR search_condition
    {{
      
      $$ = sql_add_node_to_list ( $3, $5);
      
    DBG_PRINT}}
  ;

sort_spec_list
  : sort_spec_list ',' sort_spec
    {{

      $$ = sql_add_node_to_list ($1, $3);

    DBG_PRINT}}
  | sort_spec
    {{

      $$ = $1;

    DBG_PRINT}}
  ;

sort_spec
  : expression_ SQL_ASC
    {{
      $$ = $1;
    DBG_PRINT}}

  | expression_ SQL_DESC
    {{
      $1->dt.expr.asc_flag = 1;
      $$ = $1;
    DBG_PRINT}}

  | expression_
    {{
      $$ = $1;
    DBG_PRINT}}
  ;


expression_
  : expression_ '+' term
    {{

      $$ = sql_make_expression (S_FUNC_PLUS, $1, $3, NULL);

    DBG_PRINT}}
  | expression_ '-' term
    {{

      $$ = sql_make_expression (S_FUNC_MINUS, $1, $3, NULL);

    DBG_PRINT}}
  | expression_ SQL_STRCAT term
    {{

      $$ = sql_make_expression (S_FUNC_STRCAT, $1, $3, NULL);

    DBG_PRINT}}
  | expression_ '|' term
    {{
      
      $$ = sql_make_expression (S_FUNC_OR, $1, $3, NULL);
      
    DBG_PRINT}}
  | term
    {{

      $$ = $1;

    DBG_PRINT}}
  ;

term
  : term '*' factor
    {{

      $$ = sql_make_expression (S_FUNC_TIMES, $1, $3, NULL);

    DBG_PRINT}}
  | term '/' factor
    {{

      $$ = sql_make_expression (S_FUNC_DIVIDE, $1, $3, NULL);

    DBG_PRINT}}
  | factor
    {{

      $$ = $1;

    DBG_PRINT}}
  ;

factor
  : opt_plus primary
    {{

      $$ = $2;

    DBG_PRINT}}
  | '-' primary
    {{

      $$ = sql_make_expression (S_FUNC_UNARY_MINUS, $2, NULL, NULL);

    DBG_PRINT}}
  | SQL_PRIOR primary
    {{
      $$ = sql_make_expression (S_FUNC_PRIOR, $2, NULL, NULL);
    DBG_PRINT}}
  ;

primary
  : SQL_LEVEL    %dprec 11
    {{
      
    DBG_PRINT}}

  | reserved_func    %dprec 10
    {{
      $$ = $1;
    DBG_PRINT}}

  | case_expr    %dprec 9
    {{
      $$ = $1;
    DBG_PRINT}}

  | SQL_EXTRACT '(' SQL_ID_NAME SQL_FROM expression_ ')'
    {{

      SQL_NODE_PTR tmp;
      tmp = sql_make_expression (S_FUNC_EXTRACT, $5, NULL, NULL);
      $$ = tmp;

    DBG_PRINT}}

  | literal_w_o_param  %dprec 7
    {{
      $$ = $1;
    DBG_PRINT}}

  | insert_expression  %dprec 6
    {{
      $$ = $1;
    DBG_PRINT}}

  | path_expression  %dprec 5
    {{
      $$ = $1;
    DBG_PRINT}}

  | '(' expression_list ')' %dprec 4
    {{
      $$ = $2;
    DBG_PRINT}}

  | '(' search_condition_expression opt_orderby_clause ')' %dprec 2
    {{
      
    DBG_PRINT}}

  | '(' csql_query ')' %dprec 1
    {{
      $$ = $2;
    DBG_PRINT}}
  ;

search_condition_expression
  : search_condition_expression table_op select_or_subquery
    {{
    DBG_PRINT}}

  | search_condition
    {{

      $$ = $1;

    DBG_PRINT}}
  ;

reserved_func
  : SQL_COUNT '(' '*' ')'
    {{
    DBG_PRINT}}

  | SQL_COUNT '(' of_distinct_unique expression_ ')'
    {{
    DBG_PRINT}}

  | SQL_COUNT '(' expression_ ')'
    {{
    DBG_PRINT}}

  | of_avg_max_etc '(' of_distinct_unique path_expression ')'
    {{

    DBG_PRINT}}

  | of_avg_max_etc '(' expression_ ')'
    {{
    DBG_PRINT}}

  | SQL_POSITION '(' expression_ SQL_IN expression_ ')'
    {{

      $$ = sql_make_expression (S_FUNC_POSITION, $3, $5, NULL);

    DBG_PRINT}}

  | SQL_SUBSTRING '(' expression_ SQL_FROM expression_ SQL_FOR expression_ ')'
    {{
      SQL_NODE_PTR node = sql_make_expression (S_FUNC_SUBSTRING, $3, $5, $7);
      $$ = node;
    DBG_PRINT}}

  | SQL_SUBSTRING '(' expression_ SQL_FROM expression_ ')'
    {{
      SQL_NODE_PTR node = sql_make_expression (S_FUNC_SUBSTRING, $3, $5, NULL);
      $$ = node;
    DBG_PRINT}}

  | SQL_TRIM '(' of_leading_trailing_both expression_ SQL_FROM expression_ ')'
    {{
      SQL_NODE_PTR node = sql_make_expression (S_FUNC_TRIM, $6, $4, NULL);
      $$ = node;

    DBG_PRINT}}

  | SQL_TRIM '(' of_leading_trailing_both SQL_FROM expression_ ')'
    {{

      SQL_NODE_PTR node = sql_make_expression (S_FUNC_TRIM, $5, NULL, NULL);
      $$ = node;

    DBG_PRINT}}

  | SQL_TRIM '(' expression_ SQL_FROM  expression_ ')'
    {{
      SQL_NODE_PTR node = sql_make_expression (S_FUNC_TRIM, $5, $3, NULL);
      $$ = node;

    DBG_PRINT}}

  | SQL_TRIM '(' expression_ ')'
    {{
      SQL_NODE_PTR node = sql_make_expression (S_FUNC_TRIM, $3, NULL, NULL);
      $$ = node;

    DBG_PRINT}}

  | SQL_CAST '(' expression_ SQL_AS primitive_type ')'
    {{
    DBG_PRINT}}

  | SQL_CURRENT_DATE
    {{
    DBG_PRINT}}

  | SQL_CURRENT_TIME
    {{
    DBG_PRINT}}

  | SQL_CURRENT_TIMESTAMP
    {{
    DBG_PRINT}}

  | SQL_CURRENT
    {{
    DBG_PRINT}}

  | SQL_USER
    {{
    DBG_PRINT}}

  | SQL_OCTET_LENGTH '(' expression_ ')'
    {{

      $$ = sql_make_expression (S_FUNC_OCTET_LENGTH, $3, NULL, NULL);

    DBG_PRINT}}

  | SQL_BIT_LENGTH '(' expression_ ')'
    {{

      $$ = sql_make_expression (S_FUNC_BIT_LENGTH, $3, NULL, NULL);

    DBG_PRINT}}

  | SQL_LOWER '(' expression_ ')'
    {{

      $$ = sql_make_expression (S_FUNC_LOWER, $3, NULL, NULL);

    DBG_PRINT}}

  | SQL_UPPER '(' expression_ ')'
    {{

      $$ = sql_make_expression (S_FUNC_UPPER, $3, NULL, NULL);

    DBG_PRINT}}

  | SQL_TRANSLATE '(' expression_  ',' expression_ ',' expression_ ')'
    {{

      $$ = sql_make_expression (S_FUNC_TRANSLATE, $3, $5, $7);

    DBG_PRINT}}
  ;

of_avg_max_etc
  : SQL_AVG
    {{

      $$ = S_FUNC_AVG;

    DBG_PRINT}}
  | SQL_MAX
    {{

      $$ = S_FUNC_MAX;

    DBG_PRINT}}
  | SQL_MIN
    {{

      $$ = S_FUNC_MIN;

    DBG_PRINT}}
  | SQL_SUM
    {{

      $$ = S_FUNC_SUM;

    DBG_PRINT}}
  | SQL_STDDEV
    {{

      $$ = S_FUNC_STDDEV;

    DBG_PRINT}}
  ;

of_distinct_unique
  : SQL_DISTINCT
    {{
      $$ = SQL_DISTINCT;
    }}
  | SQL_UNIQUE
    {{
      $$ = SQL_UNIQUE;
    }}
  ;

of_leading_trailing_both
  : SQL_LEADING
    {{

      $$ = SQL_LEADING;

    DBG_PRINT}}
  | SQL_TRAILING
    {{

      $$ = SQL_TRAILING;

    DBG_PRINT}}
  | SQL_BOTH
    {{

      $$ = SQL_BOTH;

    DBG_PRINT}}
  ;

case_expr
  : SQL_NULLIF '(' expression_ ',' expression_ ')'
    {{
      $$ = sql_make_expression (S_FUNC_NULLIF, $3, $5, NULL);
    DBG_PRINT}}

  | SQL_COALESCE '(' expression_list ')'
    {{
    DBG_PRINT}}

  | SQL_CASE expression_ simple_when_clause_list opt_else_expr SQL_END
    {{
    DBG_PRINT}}

  | SQL_CASE searched_when_clause_list opt_else_expr SQL_END
    {{
    DBG_PRINT}}
  ;

opt_else_expr
  : /* empty */
    {{

      $$ = NULL;

    DBG_PRINT}}
  | SQL_ELSE expression_
    {{

      $$ = $2;

    DBG_PRINT}}
  ;

simple_when_clause_list
  : simple_when_clause_list SQL_WHEN expression_ SQL_THEN expression_
    {{

      //$$ = sql_add_node_to_list ($1, $2);

    DBG_PRINT}}
  | SQL_WHEN expression_ SQL_THEN expression_
    {{

      //$$ = sql_new_list_node_and_add ($1);

    DBG_PRINT}}
  ;

searched_when_clause_list
  : searched_when_clause_list SQL_WHEN search_condition SQL_THEN expression_
    {{

      //$$ = sql_add_node_to_list ($1, $2);

    DBG_PRINT}}
  | SQL_WHEN search_condition SQL_THEN expression_
    {{

      //$$ = sql_new_list_node_and_add ($1);

    DBG_PRINT}}
  ;

search_condition
  : search_condition SQL_OR boolean_term
    {{

      $$ = sql_make_expression (S_FUNC_OR, $1, $3, NULL);

    DBG_PRINT}}
  | boolean_term
    {{

      $$ = $1;

    DBG_PRINT}}
  ;

boolean_term
  : boolean_term SQL_AND boolean_factor
    {{

      $$ = sql_make_expression (S_FUNC_AND, $1, $3, NULL);

    DBG_PRINT}}
  | boolean_factor
    {{

      $$ = $1;

    DBG_PRINT}}
  ;

boolean_factor
  : SQL_NOT predicate
    {{

      $$ = sql_make_expression (S_FUNC_NOT, $2, NULL, NULL);

    DBG_PRINT}}
  | predicate
    {{

      $$ = $1;

    DBG_PRINT}}
  ;

predicate
  : SQL_EXISTS expression_
    {{

      $$ = sql_make_expression (S_FUNC_EXISTS, $2, NULL, NULL);

    DBG_PRINT}}
  | expression_
    {{

      $$ = $1;

    DBG_PRINT}}
  | expression_ comp_op expression_
    {{
      $$ = sql_make_expression ( $2, $1, $3, NULL);
    DBG_PRINT}}

  | expression_ like_op expression_ SQL_ESCAPE escape_string_literal
    {{
      $$ = sql_make_expression ( $2, $1, $3, $5);
    DBG_PRINT}}

  | expression_ like_op expression_
    {{

      $$ = sql_make_expression ($2, $1, $3, NULL);

    DBG_PRINT}}
  | expression_ null_op
    {{

      $$ = sql_make_expression ($2, $1, NULL, NULL);

    DBG_PRINT}}
  | expression_ between_op expression_ SQL_AND expression_
    {{
      $$ = sql_make_expression ( $2, $1, $3, $5);
    DBG_PRINT}}
  | expression_ in_op expression_
    {{
      $$ = sql_make_expression ( $2, $1, $3, NULL);
    DBG_PRINT}}
  ;
  | expression_ SQL_ID_NAME
    {{
      $1->dt.expr.as_name = $2;
      $$ = $1;
    DBG_PRINT}}
  ;

comp_op
  :  '=' opt_of_all_some_any
    {{

      switch ($2)
        {
        case 0:
          $$ = S_FUNC_EQ;
          break;
        case 1:
          $$ = S_FUNC_EQ_ALL;
          break;
        case 2:
          $$ = S_FUNC_EQ_SOME;
          break;
        case 3:
          $$ = S_FUNC_EQ_SOME;
          break;
        }

    DBG_PRINT}}
  | SQL_COMP_NOT_EQ opt_of_all_some_any
    {{

      switch ($2)
        {
        case 0:
          $$ = S_FUNC_NE;
          break;
        case 1:
          $$ = S_FUNC_NE_ALL;
          break;
        case 2:
          $$ = S_FUNC_NE_SOME;
          break;
        case 3:
          $$ = S_FUNC_NE_SOME;
          break;
        }

    DBG_PRINT}}
  | '>' opt_of_all_some_any
    {{

      switch ($2)
        {
        case 0:
          $$ = S_FUNC_GT;
          break;
        case 1:
          $$ = S_FUNC_GT_ALL;
          break;
        case 2:
          $$ = S_FUNC_GT_SOME;
          break;
        case 3:
          $$ = S_FUNC_GT_SOME;
          break;
        }

    DBG_PRINT}}
  | SQL_COMP_GE opt_of_all_some_any
    {{

      switch ($2)
        {
        case 0:
          $$ = S_FUNC_GE;
          break;
        case 1:
          $$ = S_FUNC_GE_ALL;
          break;
        case 2:
          $$ = S_FUNC_GE_SOME;
          break;
        case 3:
          $$ = S_FUNC_GE_SOME;
          break;
        }

    DBG_PRINT}}
  | '<'  opt_of_all_some_any
    {{

      switch ($2)
        {
        case 0:
          $$ = S_FUNC_LT;
          break;
        case 1:
          $$ = S_FUNC_LT_ALL;
          break;
        case 2:
          $$ = S_FUNC_LT_SOME;
          break;
        case 3:
          $$ = S_FUNC_LT_SOME;
          break;
        }

    DBG_PRINT}}
  | SQL_COMP_LE opt_of_all_some_any
    {{

      switch ($2)
        {
        case 0:
          $$ = S_FUNC_LE;
          break;
        case 1:
          $$ = S_FUNC_LE_ALL;
          break;
        case 2:
          $$ = S_FUNC_LE_SOME;
          break;
        case 3:
          $$ = S_FUNC_LE_SOME;
          break;
        }

    DBG_PRINT}}
  | SQL_EQUAL_SIGN opt_of_all_some_any
    {{
    DBG_PRINT}}
  | SQL_NOT_EQUAL_SIGN opt_of_all_some_any
    {{
    DBG_PRINT}}
  ;

opt_of_all_some_any
  : /* empty */
    {{

      $$ = 0;

    DBG_PRINT}}
  | SQL_ALL
    {{

      $$ = 1;

    DBG_PRINT}}
  | SQL_SOME
    {{

      $$ = 2;

    DBG_PRINT}}
  | SQL_ANY
    {{

      $$ = 3;

    DBG_PRINT}}
  ;

like_op
  : SQL_NOT SQL_LIKE
    {{

      $$ = S_FUNC_NOT_LIKE;

    DBG_PRINT}}
  | SQL_LIKE
    {{

      $$ = S_FUNC_LIKE;

    DBG_PRINT}}
  ;

null_op
  : SQL_IS SQL_NOT SQL_NULL
    {{

      $$ = S_FUNC_IS_NOT_NULL;

    DBG_PRINT}}
  | SQL_IS SQL_NULL
    {{

      $$ = S_FUNC_IS_NULL;

    DBG_PRINT}}
  ;


between_op
  : SQL_NOT SQL_BETWEEN
    {{

      $$ = S_FUNC_NOT_BETWEEN;

    DBG_PRINT}}
  | SQL_BETWEEN
    {{

      $$ = S_FUNC_BETWEEN;

    DBG_PRINT}}
  ;

in_op
  : SQL_IN
    {{

      $$ = S_FUNC_IS_IN;

    DBG_PRINT}}
  | SQL_NOT SQL_IN
    {{

      $$ = S_FUNC_IS_NOT_IN;

    DBG_PRINT}}
  ;

path_expression
  : identifier '.' '*'
    {{
      SQL_NODE_PTR node = sql_new_node (S_NODE_NAME);
      
      if (node)
      {
        node->dt.name.name = "*";
        node->dt.name.prefix = $1;
      }
      
      $$ = node;
    }}  
  | identifier '.' identifier
    {{
      SQL_NODE_PTR node = sql_new_node (S_NODE_NAME);
      
      if (node)
      {
        node->dt.name.name = $3;
        node->dt.name.prefix = $1;
      }
      
      $$ = node;
    }}
  | identifier
    {{
      SQL_NODE_PTR node = sql_new_node (S_NODE_NAME);
      
      if (node)
      {
        node->dt.name.name = $1;
        node->dt.name.prefix = NULL;
      }
      
      $$ = node;
    }}
  | ':' identifier '.' '*'
    {{
      SQL_NODE_PTR node = sql_new_node (S_NODE_NAME);
      
      if (node)
      {
        node->dt.name.name   = "*";
        node->dt.name.prefix = $2;
      }
      
      $$ = node;
    }}
  | ':' identifier '.' identifier
    {{
      SQL_NODE_PTR node = sql_new_node (S_NODE_NAME);
      
      if (node)
      {
        node->dt.name.name = $4;
        node->dt.name.prefix = $2;
      }
      
      $$ = node;
    }}
  | ':' identifier
    {{
      SQL_NODE_PTR node = sql_new_node (S_NODE_NAME);
      
      if (node)
      {
        node->dt.name.name = $2;
        node->dt.name.prefix = NULL;
      }
      
      $$ = node;
    }}
  ;

opt_varying
  : /* empty */
    {{

      $$ = 0;

    DBG_PRINT}}
  | SQL_VARYING
    {{

      $$ = 1;

    DBG_PRINT}}
  ;

primitive_type
  : SQL_INTEGER
    {{
      $$ = LN_VT_INT32;
    DBG_PRINT}}

  | SQL_SMALLINT
    {{      
      $$ = LN_VT_INT32;
    DBG_PRINT}}

  | SQL_DOUBLE SQL_PRECISION
    {{
      $$ = LN_VT_DOUBLE;
    DBG_PRINT}}

  | SQL_DOUBLE
    {{
      $$ = LN_VT_DOUBLE;
    DBG_PRINT}}

  | SQL_DATE
    {{
      $$ = LN_VT_DATE;
    DBG_PRINT}}

  | SQL_TIME
    {{
      $$ = LN_VT_TIME;
    DBG_PRINT}}

  | SQL_TIMESTAMP
    {{
      $$ = LN_VT_TIMESTAMP;
    DBG_PRINT}}

  | SQL_DATETIME
    {{
      $$ = LN_VT_DATETIME;
    DBG_PRINT}}

  | SQL_CHAR opt_varying opt_prec_1
    {{
      $$ = LN_VT_STRING | ( ((LN_INT64)$3) << 32 );
    DBG_PRINT}}

  | SQL_VARCHAR opt_prec_1
    {{
      $$ = LN_VT_STRING | ( ((LN_INT64)$2) << 32 );
    DBG_PRINT}}

  | SQL_NATIONAL SQL_CHAR opt_varying opt_prec_1
    {{
      $$ = LN_VT_STRING | ( ((LN_INT64)$3) << 32 );
    DBG_PRINT}}

  | SQL_NCHAR  opt_varying opt_prec_1
    {{
      $$ = LN_VT_STRING | ( ((LN_INT64)$3) << 32 );
    DBG_PRINT}}

  | SQL_BIT opt_varying opt_prec_1
    {{
      $$ = LN_VT_STRING | ( ((LN_INT64)$3) << 32 );
    DBG_PRINT}}

  | SQL_NUMERIC opt_prec_2
    {{
      $$ = LN_VT_INT32 | ( ((LN_INT64)$2) << 32 );
    DBG_PRINT}}

  | SQL_FLOAT opt_prec_1
    {{
      $$ = LN_VT_DOUBLE | ( ((LN_INT64)$2) << 32 ); 
    DBG_PRINT}}
  ;

opt_prec_1
  : /* empty */
    {{

      $$ = 0;

    DBG_PRINT}}
  | '(' SQL_UNSIGNED_INTEGER ')'
    {{

      if ($2 > 0xFFFF )
      {
        // TODO Error Handling
      };
      
      $$ = $2;

    DBG_PRINT}}
  ;


opt_prec_2
  : /* empty */
    {{
      $$ = 0;
    DBG_PRINT}}
  | '(' SQL_UNSIGNED_INTEGER ')'
    {{
      if ($2 > 0xFFFF)
      {
        // TODO Error Handling
      };
      
      $$ = $2;
    DBG_PRINT}}
  | '(' SQL_UNSIGNED_INTEGER ',' SQL_UNSIGNED_INTEGER ')'
    {{
      if ($2 > 0xFFFF || $4 > 0xFFFF)
      {
          // TODO Error Handling
      };
      
      $$ = $2 | ( ((LN_INT64)$4) << 16 );
    DBG_PRINT}}
  ;

literal_w_o_param
  : SQL_UNSIGNED_INTEGER
    {{
      SQL_NODE_PTR node;
      
      node = sql_new_node (S_NODE_VALUE);
      
      if (node)
      {
        if ( ($1 >> 32) == 0 )
        {
          node->dt.value.vt = LN_VT_UINT32;
          node->dt.value.dt.intval = (int)$1;
        }
        else
        {
          node->dt.value.vt = LN_VT_UINT64;
          node->dt.value.dt.i64val = $1;
        }
      }
      
      $$ = node;

    DBG_PRINT}}
  | SQL_UNSIGNED_REAL
    {{

      SQL_NODE_PTR node;
      
      node = sql_new_node (S_NODE_VALUE);
      
      if (node)
      {
        node->dt.value.vt = LN_VT_DOUBLE;
        node->dt.value.dt.realval = $1;
      }
      
      $$ = node;

    DBG_PRINT}}
  | monetary_literal
    {{

      SQL_NODE_PTR node;
      
      node = sql_new_node (S_NODE_VALUE);
      
      if (node)
      {
        node->dt.value.vt = LN_VT_MONETARY;
        node->dt.value.dt.realval = $1;
      }
      
      $$ = node;

    DBG_PRINT}}
  | char_string_literal
    {{

      SQL_NODE_PTR node;
      
      node = sql_new_node (S_NODE_VALUE);
      
      if (node)
      {
        node->dt.value.vt = LN_VT_STRING;
        node->dt.value.dt.string.val = $1;
      }
      
      $$ = node;

    DBG_PRINT}}
  | bit_string_literal
    {{

      SQL_NODE_PTR node;
      
      node = sql_new_node (S_NODE_VALUE);
      
      if (node)
      {
        node->dt.value.vt = LN_VT_STRING;
        node->dt.value.dt.string.val = $1;
      }
      
      $$ = node;

    DBG_PRINT}}
  | host_param_input
    {{
      
      SQL_NODE_PTR node = sql_new_node(S_NODE_NAME);
      if (node)
      {
        node->dt.name.name = "?:";
        node->dt.name.flag = (int)$1;
      }
      
      $$ = node;

    DBG_PRINT}}
  | SQL_NULL
    {{
      SQL_NODE_PTR node;
      
      node = sql_new_node (S_NODE_VALUE);
      
      if (node)
      {
        node->dt.value.vt = LN_VT_NULL;
      }
      
      $$ = node;

    DBG_PRINT}}
  | date_or_time_literal
    {{
      $$ = $1;
    DBG_PRINT}}
  ;

/* opt_id, id_list */

opt_id
  : /* empty */
    {{

      $$ = NULL;

    DBG_PRINT}}
  | identifier
    {{

      $$ = $1;

    DBG_PRINT}}
  ;

id_list
  : id_list ',' identifier
    {{

      sql_string_list_add ( (SQL_STRING_LIST*)&($1), $3);
      
      $$ = $1;

    DBG_PRINT}}
  | identifier
    {{

      $$.size = 0;
      
      sql_string_list_add (&$$, $1);

    DBG_PRINT}}
  ;

identifier
  : SQL_ID_NAME
    {{
      $$ = $1;
    DBG_PRINT}}

  | SQL_BracketDelimitedIdName
    {{
      $$ = $1;
    DBG_PRINT}}

  | SQL_MEMBERS
    {{
      $$ = $1;
    DBG_PRINT}}

  | SQL_PASSWORD
    {{
      $$ = $1;
    DBG_PRINT}}

  | SQL_STDDEV
    {{
      $$ = $1;
    DBG_PRINT}}
  ;

escape_string_literal
  : char_string_literal
    {{

      SQL_NODE_PTR node = sql_new_node (S_NODE_VALUE);
      
      if (node)
      {
        node->dt.value.vt = LN_VT_STRING;
        node->dt.value.dt.string.val = $1;
        node->dt.value.dt.string.buf_size = 0;
        node->dt.value.dt.string.size =0;
      }
      
      $$ = node;

    DBG_PRINT}}
  | host_param_input
    {{
      SQL_NODE_PTR node = sql_new_node (S_NODE_VALUE);
      
      if (node)
      {
        node->dt.value.vt = LN_VT_INT32;
        node->dt.value.dt.intval = (int)$1;
      }
      
      $$ = node;

    DBG_PRINT}}
        ;


char_string_literal
  : char_string_literal SQL_CHAR_STRING
    {{
      $$ = sql_strcat ($1, $2, NULL);
    DBG_PRINT}}
  | SQL_CHAR_STRING
    {{
      $$ = $1;
    DBG_PRINT}}
  | SQL_NCHAR_STRING
    {{
      $$ = $1;
    DBG_PRINT}}
  ;


bit_string_literal
  : bit_string_literal SQL_CHAR_STRING
    {{
      $$ = sql_strcat ($1, $2, NULL);
    DBG_PRINT}}
  | SQL_BIT_STRING
    {{
      $$ = $1;
    DBG_PRINT}}
  | SQL_HEX_STRING
    {{
      $$ = $1;
    DBG_PRINT}}
  ;


monetary_literal
  : SQL_DOLLAR_SIGN of_integer_real_literal
    {{
      $$ = $2;
    DBG_PRINT}}
  | SQL_WON_SIGN of_integer_real_literal
    {{
      $$ = $2;
    DBG_PRINT}}
  ;

of_integer_real_literal
  : opt_plus SQL_UNSIGNED_INTEGER
    {{

      $$ = (double) $2;

    DBG_PRINT}}
  | '-' SQL_UNSIGNED_INTEGER
    {{

      $$ = - (double)$2;

    DBG_PRINT}}

  | opt_plus SQL_UNSIGNED_REAL
    {{

      $$ = $2;

    DBG_PRINT}}
  | '-' SQL_UNSIGNED_REAL
    {{

      $$ = - $2;

    DBG_PRINT}}
  ;

date_or_time_literal
  : SQL_DATE char_string_literal
    {{
      SQL_NODE_PTR node;
      
      node = sql_new_node (S_NODE_VALUE);
      
      if (node)
      {
        node->dt.value.vt = LN_VT_DATE;
      }
      
      $$ = node;

    DBG_PRINT}}
  | SQL_TIME char_string_literal
    {{
      SQL_NODE_PTR node;
      
      node = sql_new_node (S_NODE_VALUE);
      
      if (node)
      {
        node->dt.value.vt = LN_VT_TIME;
      }
      
      $$ = node;
    DBG_PRINT}}
  | SQL_TIMESTAMP char_string_literal
    {{
      SQL_NODE_PTR node;
      
      node = sql_new_node (S_NODE_VALUE);
      
      if (node)
      {
        node->dt.value.vt = LN_VT_TIMESTAMP;
      }
      
      $$ = node;
    DBG_PRINT}}
  | SQL_DATETIME char_string_literal
    {{
      SQL_NODE_PTR node;
      
      node = sql_new_node (S_NODE_VALUE);
      
      if (node)
      {
        node->dt.value.vt = LN_VT_DATETIME;
      }
      
      $$ = node;
    DBG_PRINT}}
  ;


%%

